#include "engine.hpp"

#include <iostream>

///////////////////////////////////////////////////////////////////////////////
/// State management
///////////////////////////////////////////////////////////////////////////////
bool Engine::init(int width, int height, int bpp, std::string title, int aa) {
	window.Create(sf::VideoMode(width, height, bpp), title, sf::Style::Close, aa);
	window.OptimizeForNonOpenGL(true);
	window.UseVerticalSync(true);
	window.SetFramerateLimit(60);
	
	sf::Randomizer::SetSeed(time(NULL));
    
	running = true;
	
	return true;
}

void Engine::cleanup() {
	while(!states.empty()) {
		states.back()->cleanup();
		states.pop_back();
	}
	
	clearResources();
}
void Engine::changeState(GameState *state) {
	if(!states.empty()) {
		states.back()->cleanup();
		states.pop_back();
	}
	
	states.push_back(state);
	states.back()->init(this);
}

void Engine::pushState(GameState *state) {
	if(!states.empty())
		states.back()->pause();
	
	states.push_back(state);
	states.back()->init(this);
}

void Engine::popState() {
	states.back()->cleanup();
	states.pop_back();
	
	if(!states.empty())
		states.back()->resume();
}

///////////////////////////////////////////////////////////////////////////////
/// Main loop elements
///////////////////////////////////////////////////////////////////////////////
void Engine::handleEvents() {
	if(!states.size()) running = false;
	
	sf::Event event;
	while(window.GetEvent(event)) {
		if(event.Type == sf::Event::Closed) {
			// TODO: voir pour passer ça au GameState courant
			quit();
		}
		
		if(states.empty()) continue;
		
		for(std::map<int, Player>::iterator iPlayer = players.begin(); iPlayer != players.end(); iPlayer++) {
			Player& player = (*iPlayer).second;
			
			for(int i = 0; i < PlayerEvent::Count; i++) {
				switch(player.actions[i].type) {
					case PlayerAction::Key:
					{
						if((event.Type == sf::Event::KeyPressed)
						&& (event.Key.Code == player.actions[i].keyCode)) {
							player.actions[i].state = true;
							
							PlayerEvent e((*iPlayer).first, PlayerEvent::Type(i), true);
							states.back()->processEvent(this, e);
						}
						
						else if((event.Type == sf::Event::KeyReleased)
						&& (event.Key.Code == player.actions[i].keyCode)) {
							player.actions[i].state = false;
							
							PlayerEvent e((*iPlayer).first, PlayerEvent::Type(i), false);
							states.back()->processEvent(this, e);
						}
						break;
					}
					case PlayerAction::JoyAxisPositive:
					{
						if((event.Type == sf::Event::JoyMoved)
						&& (event.JoyMove.JoystickId == player.actions[i].joyId)
						&& (event.JoyMove.Axis == player.actions[i].joyAxis)
						&& (event.JoyMove.Position > 0)) {
							player.actions[i].state = true;
							
							PlayerEvent e((*iPlayer).first, PlayerEvent::Type(i), true);
							states.back()->processEvent(this, e);
						}
						
						else if((event.Type == sf::Event::JoyMoved)
						&& (event.JoyMove.JoystickId == player.actions[i].joyId)
						&& (event.JoyMove.Axis == player.actions[i].joyAxis)
						&& (event.JoyMove.Position == 0)
						&& (player.actions[i].state)) {
							player.actions[i].state = false;
							
							PlayerEvent e((*iPlayer).first, PlayerEvent::Type(i), false);
							states.back()->processEvent(this, e);
						}
						break;
					}
					case PlayerAction::JoyAxisNegative:
					{
						if((event.Type == sf::Event::JoyMoved)
						&& (event.JoyMove.JoystickId == player.actions[i].joyId)
						&& (event.JoyMove.Axis == player.actions[i].joyAxis)
						&& (event.JoyMove.Position < 0)) {
							player.actions[i].state = true;
							
							PlayerEvent e((*iPlayer).first, PlayerEvent::Type(i), true);
							states.back()->processEvent(this, e);
						}
						
						else if((event.Type == sf::Event::JoyMoved)
						&& (event.JoyMove.JoystickId == player.actions[i].joyId)
						&& (event.JoyMove.Axis == player.actions[i].joyAxis)
						&& (event.JoyMove.Position == 0)
						&& (player.actions[i].state)) {
							player.actions[i].state = false;
							
							PlayerEvent e((*iPlayer).first, PlayerEvent::Type(i), false);
							states.back()->processEvent(this, e);
						}
						break;
					}
					case PlayerAction::JoyButton:
					{
						if((event.Type == sf::Event::JoyButtonPressed)
						&& (event.JoyButton.JoystickId == player.actions[i].joyId)
						&& (event.JoyButton.Button == player.actions[i].joyButton)) {
							player.actions[i].state = true;
							
							PlayerEvent e((*iPlayer).first, PlayerEvent::Type(i), true);
							states.back()->processEvent(this, e);
						}
						
						else if((event.Type == sf::Event::JoyButtonReleased)
						&& (event.JoyMove.JoystickId == player.actions[i].joyId)
						&& (event.JoyButton.Button == player.actions[i].joyButton)) {
							player.actions[i].state = false;
							
							PlayerEvent e((*iPlayer).first, PlayerEvent::Type(i), false);
							states.back()->processEvent(this, e);
						}
						break;
						break;
					}
				}
			}
		}
		
	}
}

void Engine::update() {
	if(states.size()) states.back()->update(this);
	else running = false;
}

void Engine::draw() {
	if(states.size()) states.back()->draw(this);
	else running = false;
	window.Display();
}

///////////////////////////////////////////////////////////////////////////////
/// Resources management
///////////////////////////////////////////////////////////////////////////////
sf::Image& Engine::getImage(std::string filename) {
	if(images.find(filename) == images.end()) images[filename].LoadFromFile(filename);
	return images[filename];
}

sf::SoundBuffer& Engine::getSound(std::string filename) {
	if(sounds.find(filename) == sounds.end()) sounds[filename].LoadFromFile(filename);
	return sounds[filename];
}

/*sf::Music& Engine::getMusic(std::string filename) {
	if(musics.find(filename) == musics.end()) musics[filename].Open(filename);
	return musics[filename];
}*/

sf::Font& Engine::getFont(std::string filename) {
	if(fonts.find(filename) == fonts.end()) fonts[filename].LoadFromFile(filename);
	return fonts[filename];
}

void Engine::clearResources() {
	images.clear();
	sounds.clear();
	fonts.clear();
}

////////////////////////////////////////////////////////////////////////////////
/// Players
////////////////////////////////////////////////////////////////////////////////
/*bool Engine::getPlayerEvent(PlayerEvent& playerEvent) {
	if(!playerEvents.empty()) {
		playerEvent = playerEvents.front();
		playerEvents.pop();
		
		return true;
	}
	
	return false;
}*/
